﻿using System;
using System.Collections;
using GeoAPI.Geometries;
using NetTopologySuite.Algorithm;
using NetTopologySuite.GeometriesGraph;
using NetTopologySuite.Utilities;

namespace NetTopologySuite.Operation.Buffer
{
	internal class RightmostEdgeFinder
	{
		public DirectedEdge Edge
		{
			get
			{
				return this.orientedDe;
			}
		}

		public Coordinate Coordinate
		{
			get
			{
				return this.minCoord;
			}
		}

		public void FindEdge(IList dirEdgeList)
		{
			foreach (object obj in dirEdgeList)
			{
				DirectedEdge directedEdge = (DirectedEdge)obj;
				if (directedEdge.IsForward)
				{
					this.CheckForRightmostCoordinate(directedEdge);
				}
			}
			Assert.IsTrue(this.minIndex != 0 || this.minCoord.Equals(this.minDe.Coordinate), "inconsistency in rightmost processing");
			if (this.minIndex == 0)
			{
				this.FindRightmostEdgeAtNode();
			}
			else
			{
				this.FindRightmostEdgeAtVertex();
			}
			this.orientedDe = this.minDe;
			if (this.GetRightmostSide(this.minDe, this.minIndex) == Positions.Left)
			{
				this.orientedDe = this.minDe.Sym;
			}
		}

		private void FindRightmostEdgeAtNode()
		{
			DirectedEdgeStar directedEdgeStar = (DirectedEdgeStar)this.minDe.Node.Edges;
			this.minDe = directedEdgeStar.GetRightmostEdge();
			if (!this.minDe.IsForward)
			{
				this.minDe = this.minDe.Sym;
				this.minIndex = this.minDe.Edge.Coordinates.Length - 1;
			}
		}

		private void FindRightmostEdgeAtVertex()
		{
			Coordinate[] coordinates = this.minDe.Edge.Coordinates;
			Assert.IsTrue(this.minIndex > 0 && this.minIndex < coordinates.Length, "rightmost point expected to be interior vertex of edge");
			Coordinate coordinate = coordinates[this.minIndex - 1];
			Coordinate coordinate2 = coordinates[this.minIndex + 1];
			int num = CGAlgorithms.ComputeOrientation(this.minCoord, coordinate2, coordinate);
			bool flag = false;
			if (coordinate.Y < this.minCoord.Y && coordinate2.Y < this.minCoord.Y && num == 1)
			{
				flag = true;
			}
			else if (coordinate.Y > this.minCoord.Y && coordinate2.Y > this.minCoord.Y && num == -1)
			{
				flag = true;
			}
			if (flag)
			{
				this.minIndex--;
			}
		}

		private void CheckForRightmostCoordinate(DirectedEdge de)
		{
			Coordinate[] coordinates = de.Edge.Coordinates;
			for (int i = 0; i < coordinates.Length - 1; i++)
			{
				if (this.minCoord == null || coordinates[i].X > this.minCoord.X)
				{
					this.minDe = de;
					this.minIndex = i;
					this.minCoord = coordinates[i];
				}
			}
		}

		private Positions GetRightmostSide(DirectedEdge de, int index)
		{
			Positions rightmostSideOfSegment = this.GetRightmostSideOfSegment(de, index);
			if (rightmostSideOfSegment < Positions.On)
			{
				rightmostSideOfSegment = this.GetRightmostSideOfSegment(de, index - 1);
			}
			if (rightmostSideOfSegment < Positions.On)
			{
				this.minCoord = null;
				this.CheckForRightmostCoordinate(de);
			}
			return rightmostSideOfSegment;
		}

		private Positions GetRightmostSideOfSegment(DirectedEdge de, int i)
		{
			Coordinate[] coordinates = de.Edge.Coordinates;
			if (i < 0 || i + 1 >= coordinates.Length)
			{
				return Positions.Parallel;
			}
			if (coordinates[i].Y == coordinates[i + 1].Y)
			{
				return Positions.Parallel;
			}
			Positions result = Positions.Left;
			if (coordinates[i].Y < coordinates[i + 1].Y)
			{
				result = Positions.Right;
			}
			return result;
		}

		private int minIndex = -1;

		private Coordinate minCoord;

		private DirectedEdge minDe;

		private DirectedEdge orientedDe;
	}
}
